package gui;

import gui.initiatives.AbstractClockControl;
import gui.initiatives.ClockControlPull;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import common.Constants;
import common.SimulationSettings;

public class UserControlPanel extends JPanel {
  private static final long serialVersionUID = -4563608487057327554L;

  private final EarthPanel pnlEarth;
  private final AbstractClockControl pnlClockControls;
  private JSpinner gridSpacing;
  private JSpinner simTimeStep;
  private JSlider displayRate;
  private JSlider bufferPushRate;
  private JButton btnDrawGrid;
  private SimulationSettings settings;  
  
  public UserControlPanel(EarthPanel pnlEarth, SimulationSettings settings) {
    super();
    setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
    setPreferredSize(new Dimension(100,220));
    setMaximumSize(new Dimension(Constants.FRAME_WIDTH,220));
    
    this.settings = settings;    
    this.pnlEarth = pnlEarth;
    this.pnlClockControls = new ClockControlPull(pnlEarth, settings);
        
    JPanel left = new JPanel();
    left.setLayout(new BoxLayout(left, BoxLayout.PAGE_AXIS));
    left.add(Box.createVerticalGlue());
    left.add(getSimControls());
    left.add(Box.createVerticalStrut(10));
    left.add(getTimerControls());
    left.add(Box.createVerticalGlue());
    
    JPanel right = new JPanel();
    right.setLayout(new BoxLayout(right, BoxLayout.PAGE_AXIS));
    right.add(Box.createVerticalGlue());
    right.add(getPresentationControls());
    right.add(Box.createVerticalGlue());
    
    add(Box.createGlue());
    add(left);
    add(Box.createHorizontalStrut(10));
    add(right);
    add(Box.createGlue()); 
  }
  
  private JPanel getSimControls() {
    JPanel pnlSimControls = new JPanel();
    pnlSimControls.setLayout(new BoxLayout(pnlSimControls, BoxLayout.PAGE_AXIS));
    pnlSimControls.setBorder(BorderFactory.createTitledBorder("Simulation Settings"));
    pnlSimControls.setAlignmentX(Component.LEFT_ALIGNMENT);
    
    Dimension dim = new Dimension(290,90);
    pnlSimControls.setPreferredSize(dim);
    pnlSimControls.setMaximumSize(dim);
    
    pnlSimControls.add(getGridSpacingControl());
    pnlSimControls.add(Box.createVerticalStrut(10));
    pnlSimControls.add(getTimeStepControl());    
    return pnlSimControls;
  }
  
  private JPanel getGridSpacingControl() {
    gridSpacing = new JSpinner(
    new SpinnerNumberModel(Constants.DEFAULT_GRID_SPACING, 
                           Constants.MIN_GRID_SPACING, 
                           Constants.MAX_GRID_SPACING, 1));
    gridSpacing.setPreferredSize(new Dimension(75, 20));
    gridSpacing.setMaximumSize(new Dimension(75, 20));
    gridSpacing.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        settings.setGridSpacing(Integer.parseInt(gridSpacing.getValue().toString()));
      };
    });

    btnDrawGrid = new JButton("Draw Grid");
    btnDrawGrid.setPreferredSize(new Dimension(100, 20));
    btnDrawGrid.setMaximumSize(new Dimension(100, 20));
    btnDrawGrid.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
       pnlEarth.drawGrid(settings.getGridSpacing());
       settings.setRadius(pnlEarth.getRadius());
       pnlClockControls.getEngine().setGridSpacing(settings.getGridSpacing(), settings.getRadius());
      }
    });
    
    JPanel pnlGrid = new JPanel();
    pnlGrid.setLayout(new BoxLayout(pnlGrid, BoxLayout.LINE_AXIS));
    pnlGrid.setAlignmentX(Component.LEFT_ALIGNMENT);
    pnlGrid.add(new JLabel("Grid Spacing: "));
    pnlGrid.add(gridSpacing);
    pnlGrid.add(btnDrawGrid);
    return pnlGrid;
  }
  
  private JPanel getTimeStepControl() {
    simTimeStep = new JSpinner(
    new SpinnerNumberModel(Constants.DEFAULT_SIM_TIME_STEP, 
                           Constants.MIN_SIM_TIME_STEP, 
                           Constants.MAX_SIM_TIME_STEP, 1));
    simTimeStep.setPreferredSize(new Dimension(75, 25));
    simTimeStep.setMaximumSize(new Dimension(75, 25));
    simTimeStep.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        JSpinner spn = (JSpinner) e.getSource();
        settings.setSimTimeStep(Integer.parseInt(spn.getValue().toString()));
      };
    });

    JPanel pnlSimTime = new JPanel();
    pnlSimTime.setLayout(new BoxLayout(pnlSimTime, BoxLayout.LINE_AXIS));
    pnlSimTime.setAlignmentX(Component.LEFT_ALIGNMENT);
    pnlSimTime.add(new JLabel("Simulation Time Step: "));
    pnlSimTime.add(simTimeStep);
    pnlSimTime.add(new JLabel(" (minutes)"));
    return pnlSimTime;
  }
  
  private JPanel getPresentationControls() {
    JPanel pnlDisplay = new JPanel();
    pnlDisplay.setLayout(new BoxLayout(pnlDisplay, BoxLayout.PAGE_AXIS));
    pnlDisplay.setBorder(BorderFactory.createTitledBorder("Presentation Controls"));
    
    Dimension dim = new Dimension(290,180);
    pnlDisplay.setPreferredSize(dim);
    pnlDisplay.setMaximumSize(dim);
    
    pnlDisplay.add(getOpacityControl());
    pnlDisplay.add(Box.createVerticalStrut(10));
    pnlDisplay.add(getDisplayRateControl());
    pnlDisplay.add(Box.createVerticalStrut(10));
    pnlDisplay.add(getBufferRateControl());
    return pnlDisplay;
  }
  
  private JPanel getTimerControls() {
    JPanel pnlTimer = new JPanel();
    pnlTimer.setLayout(new BoxLayout(pnlTimer, BoxLayout.LINE_AXIS));
    pnlTimer.setBorder(BorderFactory.createTitledBorder("Timer"));
    pnlTimer.setAlignmentX(Component.LEFT_ALIGNMENT);
    pnlTimer.add(pnlClockControls);    
    return pnlTimer;
  }
  
  private JPanel getOpacityControl() {
    JSlider imageOpacity = new JSlider(0, 100, (int)(Constants.OPACITY*100));
    imageOpacity.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        JSlider slider = (JSlider) e.getSource();
        pnlEarth.setMapOpacity(slider.getValue() / 100f);
      };
    });
    imageOpacity.setPreferredSize(new Dimension(150, 20));
    imageOpacity.setMaximumSize(new Dimension(150, 20));
    
    JPanel pnlOpacity = new JPanel();
    pnlOpacity.setLayout(new BoxLayout(pnlOpacity, BoxLayout.LINE_AXIS));
    pnlOpacity.setAlignmentX(Component.LEFT_ALIGNMENT);
    pnlOpacity.add(new JLabel("Image opacity:"));
    pnlOpacity.add(imageOpacity);
    return pnlOpacity;        
  }
  
  private JPanel getDisplayRateControl() {
    displayRate = new JSlider(Constants.MIN_DISPLAY_RATE, 
                              Constants.MAX_DISPLAY_RATE, 
                              Constants.DEFAULT_DISPLAY_RATE);
    
    displayRate.setMajorTickSpacing(Constants.MAX_DISPLAY_RATE/2);
    displayRate.setPaintTicks(true);
    Hashtable labelTable = new Hashtable();
    labelTable.put( new Integer( Constants.MIN_DISPLAY_RATE ), new JLabel("per ms") );
    labelTable.put( new Integer( Constants.MAX_DISPLAY_RATE/2 ), new JLabel("per half sec") );
    labelTable.put( new Integer( Constants.MAX_DISPLAY_RATE ), new JLabel("per sec") );
    displayRate.setLabelTable( labelTable );
    displayRate.setPaintLabels(true);
    
    displayRate.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        JSlider slider = (JSlider) e.getSource();
        pnlClockControls.adjustDisplayRate(slider.getValue());
      };
    });
    displayRate.setPreferredSize(new Dimension(200, 50));
    displayRate.setMaximumSize(new Dimension(200, 50));
    
    JPanel pnlDisplayRate = new JPanel();
    pnlDisplayRate.setLayout(new BoxLayout(pnlDisplayRate, BoxLayout.LINE_AXIS));
    pnlDisplayRate.setAlignmentX(Component.LEFT_ALIGNMENT);
    pnlDisplayRate.add(new JLabel("Display Rate: "));
    pnlDisplayRate.add(displayRate);
    return pnlDisplayRate;
  }
  
  private JPanel getBufferRateControl() {
    bufferPushRate = new JSlider(Constants.MIN_DISPLAY_RATE, 
                              Constants.MAX_DISPLAY_RATE, 
                              Constants.BUFFER_PUSH_RATE);
    
    bufferPushRate.setMajorTickSpacing(Constants.MAX_DISPLAY_RATE/2);
    bufferPushRate.setPaintTicks(true);
    Hashtable labelTable = new Hashtable();
    labelTable.put( new Integer( Constants.MIN_DISPLAY_RATE ), new JLabel("per ms") );
    labelTable.put( new Integer( Constants.MAX_DISPLAY_RATE/2 ), new JLabel("per half sec") );
    labelTable.put( new Integer( Constants.MAX_DISPLAY_RATE ), new JLabel("per sec") );
    bufferPushRate.setLabelTable( labelTable );
    bufferPushRate.setPaintLabels(true);
    
    JLabel lbl = new JLabel("Buffer Push Rate: ");
    if(settings.getInitiative().equals(Constants.INITIATIVE_BUFF)) {
      bufferPushRate.addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          JSlider slider = (JSlider) e.getSource();
          pnlClockControls.adjustBufferRate(slider.getValue());
        };
      });
      bufferPushRate.setPreferredSize(new Dimension(200, 50));
      bufferPushRate.setMaximumSize(new Dimension(200, 50));
    }
    else {
      //we'll keep this control in even if its disabled just to keep the UI spacing clean
      bufferPushRate.setEnabled(false);
      lbl.setEnabled(false);
    }    
    
    JPanel pnlBufferRate = new JPanel();
    pnlBufferRate.setLayout(new BoxLayout(pnlBufferRate, BoxLayout.LINE_AXIS));
    pnlBufferRate.setAlignmentX(Component.LEFT_ALIGNMENT);
    pnlBufferRate.add(lbl);
    pnlBufferRate.add(bufferPushRate);    
    return pnlBufferRate;
  }

}
